במדריך הזה נלמד איך להשתמש ב-Captcha שהייתה צריכה להיות בטופס שיצרנו במדריך הקודם באמצעות הפריימוורק Yii של PHP.
בכדי להגיע לחלק א' של המדריך ל-Yii לחצו כאן; חלק ב'; חלק ג'; חלק ד'; חלק ה'.
איזה כיף ש-Yii מאפשרת לעבוד עם captcha בקלות :-)
כפי שכתבתי בכותרת מעל, Yii נותנת לנו אפשרות לעבוד עם Captcha בקלות כל כך, שזה ממש כיף. :)
דבר ראשון, בכל קונטרולר שאנו נשתמש ב-Captcha אנחנו נכתוב את זה:
public function actions()
{
return array
(
'captcha' => array
(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'testLimit'=>3,
)
);
}
{
return array
(
'captcha' => array
(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'testLimit'=>3,
)
);
}
באמצעות הקוד הזה אנחנו בעצם מגדירים את ההגדרות של ה-Captcha שלנו. אפשר להבין מה כל הגדרה עושה לפי השם שלה. D:
ובתוך הקונטרולר זה נראה ככה:
<?php
class AccountController extends CController
{
public $layout = 'header';
public function actions()
{
return array
(
'captcha' => array
(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'testLimit'=>3,
)
);
}
public function actionRegister()
{
$model = new RegisterForm();
if(isset($_POST['RegisterForm']))
{
$model->attributes = $_POST['RegisterForm'];
if($model->validate())
{
print "Work!";
}
}
$this->render('register',array('model'=>$model));
}
}
?>
class AccountController extends CController
{
public $layout = 'header';
public function actions()
{
return array
(
'captcha' => array
(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'testLimit'=>3,
)
);
}
public function actionRegister()
{
$model = new RegisterForm();
if(isset($_POST['RegisterForm']))
{
$model->attributes = $_POST['RegisterForm'];
if($model->validate())
{
print "Work!";
}
}
$this->render('register',array('model'=>$model));
}
}
?>
עכשיו בואו נציג את ה-Captcha בדף ההרשמה.
נפתח את טופס ההרשמה ונוסיף במקום של ה-Captcha את זה:
<?php $this->widget('CCaptcha'); ?>
כאן אין begin או end, כי זה מרנדר ישירות בלי שאנחנו כותבים משהו באמצע.
זה כאילו אנחנו כותבים:
<?php $this->beginWidget('CCaptcha'); $this->endWidget(); ?>
שאין שום דבר באמצע...
מה שאומר שהקוד אמור הרשמה נראה ככה:
<h1>הירשם</h1>
<?php $form = $this->beginWidget('CActiveForm'); ?>
<table>
<tr>
<td><?php echo $form->labelEx($model, 'username'); ?></td>
<td><?php echo $form->textField($model, 'username'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'username'); ?></span></td>
</tr>
<tr>
<td><?php echo $form->labelEx($model, 'password'); ?></td>
<td><?php echo $form->passwordField($model, 'password'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'password'); ?></span></td>
<tr>
<td><?php echo $form->labelEx($model, 'password2'); ?></td>
<td><?php echo $form->passwordField($model, 'password2'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'password2'); ?></span></td>
<tr>
<td><?php echo $form->labelEx($model, 'email'); ?></td>
<td><?php echo $form->textField($model, 'email'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'email'); ?></span></td>
</tr>
</table>
<b style="font-size:16px"><?php echo $form->labelEx($model, 'verifyCode'); ?></b><br />
<span style="color:#ff0000"><?php echo $form->error($model, 'verifyCode'); ?></span><br />
<?php $this->widget('CCaptcha'); ?><br />
<?php echo $form->textField($model, 'verifyCode'); ?>
<br />
<?php echo CHtml::submitButton('התחבר'); ?>
<?php $this->endWidget(); ?>
<?php $form = $this->beginWidget('CActiveForm'); ?>
<table>
<tr>
<td><?php echo $form->labelEx($model, 'username'); ?></td>
<td><?php echo $form->textField($model, 'username'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'username'); ?></span></td>
</tr>
<tr>
<td><?php echo $form->labelEx($model, 'password'); ?></td>
<td><?php echo $form->passwordField($model, 'password'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'password'); ?></span></td>
<tr>
<td><?php echo $form->labelEx($model, 'password2'); ?></td>
<td><?php echo $form->passwordField($model, 'password2'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'password2'); ?></span></td>
<tr>
<td><?php echo $form->labelEx($model, 'email'); ?></td>
<td><?php echo $form->textField($model, 'email'); ?></td>
<td><span style="color:#ff0000"><?php echo $form->error($model, 'email'); ?></span></td>
</tr>
</table>
<b style="font-size:16px"><?php echo $form->labelEx($model, 'verifyCode'); ?></b><br />
<span style="color:#ff0000"><?php echo $form->error($model, 'verifyCode'); ?></span><br />
<?php $this->widget('CCaptcha'); ?><br />
<?php echo $form->textField($model, 'verifyCode'); ?>
<br />
<?php echo CHtml::submitButton('התחבר'); ?>
<?php $this->endWidget(); ?>
אם נריץ עכשיו את האתר נקבל שגיאה, כי התיקייה assets, התיקייה בה Yii משתמשת בצד הלקוח בשביל ה-Captcha, לא קיימת.
אז בואו ניצור אותה - לא ליצור אותה בתיקייה protected, אלא בתיקייה הראשית של האתר.
אבל אם לא נרשום את קוד האימות הנכון ב-Captcha, לא נקבל שגיאה כי לא רשמנו בחוקים ש-verifyCode אמור להיות Captcha.
כדי להגדיר את זה נוסיף ל-rules את הקוד הבא:
array('verifyCode', 'captcha', 'message' => 'קוד האבטחה אינו תקין')
captcha בודק תקינות Captcha של שדה.
מה שאומר שהמחלקה של ההרשמה נראית כך:
<?php
class RegisterForm extends CFormModel
{
public $username; // השדה של שם המשתמש
public $password; // השדה של הסיסמה
public $password2; // השדה של אימות הסיסמה
public $email; // השדה של הדואר האלקטרוני
public $verifyCode; // השדה של הקאפצ'ה
public function rules()
{
return array
(
array('username', 'length', 'allowEmpty' => false, 'min' => 4, 'max' => 16, 'tooShort' => 'מספר התווים בשם המשתמש חייב להיות לפחות 4 תווים', 'tooLong' => 'בשם המשתמש חייבים להיות עד 16 תווים ולא יותר'), // בודק את כמות התווים בשם המשתמש
array('username', 'unique', 'className' => 'Account', 'message' => 'שם המשתמש נמצא במסד'), // בודק אם שם המשתמש לא נמצא במסד
array('password', 'length', 'allowEmpty' => false, 'min' => 6, 'tooShort' => 'מספר התווים בסיסמה חייב להיות לפחות 6'), // בדיקת כמות התווים בסיסמה
array('password2', 'compare', 'compareAttribute' => 'password', 'message' => 'אימות הסיסמה אינו זהה לסיסמה'), // בודקים אם אימות הסיסמה והסיסמה זהים
array('email', 'unique', 'className' => 'Account', 'message' => 'הדואר האלקטרוני נמצא במסד'), // בודק אם האימייל לא נמצא במסד
array('email', 'email', 'allowEmpty' => false, 'checkMX' => true, 'message' => 'הדואר האלקטרוני אינו תקין') // בודק את התקינות של האימייל
array('verifyCode', 'captcha', 'message' => 'קוד האבטחה אינו תקין') // בדיקת קוד אבטחה
);
}
public function attributeLabels()
{
return array
(
'username' => 'שם משתמש',
'password' => 'סיסמה',
'password2' => 'אימות סיסמה',
'email' => 'דואר אלקטרוני',
'verifyCode' => 'קוד אבטחה'
);
}
}
?>
class RegisterForm extends CFormModel
{
public $username; // השדה של שם המשתמש
public $password; // השדה של הסיסמה
public $password2; // השדה של אימות הסיסמה
public $email; // השדה של הדואר האלקטרוני
public $verifyCode; // השדה של הקאפצ'ה
public function rules()
{
return array
(
array('username', 'length', 'allowEmpty' => false, 'min' => 4, 'max' => 16, 'tooShort' => 'מספר התווים בשם המשתמש חייב להיות לפחות 4 תווים', 'tooLong' => 'בשם המשתמש חייבים להיות עד 16 תווים ולא יותר'), // בודק את כמות התווים בשם המשתמש
array('username', 'unique', 'className' => 'Account', 'message' => 'שם המשתמש נמצא במסד'), // בודק אם שם המשתמש לא נמצא במסד
array('password', 'length', 'allowEmpty' => false, 'min' => 6, 'tooShort' => 'מספר התווים בסיסמה חייב להיות לפחות 6'), // בדיקת כמות התווים בסיסמה
array('password2', 'compare', 'compareAttribute' => 'password', 'message' => 'אימות הסיסמה אינו זהה לסיסמה'), // בודקים אם אימות הסיסמה והסיסמה זהים
array('email', 'unique', 'className' => 'Account', 'message' => 'הדואר האלקטרוני נמצא במסד'), // בודק אם האימייל לא נמצא במסד
array('email', 'email', 'allowEmpty' => false, 'checkMX' => true, 'message' => 'הדואר האלקטרוני אינו תקין') // בודק את התקינות של האימייל
array('verifyCode', 'captcha', 'message' => 'קוד האבטחה אינו תקין') // בדיקת קוד אבטחה
);
}
public function attributeLabels()
{
return array
(
'username' => 'שם משתמש',
'password' => 'סיסמה',
'password2' => 'אימות סיסמה',
'email' => 'דואר אלקטרוני',
'verifyCode' => 'קוד אבטחה'
);
}
}
?>
אוקיי, התנאים עובדים, הטופס עובד, אבל לא הוספנו את המשתמש לטופס!
עכשיו בשביל מה היה את המדריך הקודם? בשביל שנדע איך להוסיף טורים לטופס.
אז אין צורך להסביר נכון?
$account = new Account();
$account->username = $model->username;
$account->password = md5($model->password);
$account->email = $model->email;
$account->ip = Yii::app()->request->userHostAddress;
$account->save();
$this->redirect('index.php');
$account->username = $model->username;
$account->password = md5($model->password);
$account->email = $model->email;
$account->ip = Yii::app()->request->userHostAddress;
$account->save();
$this->redirect('index.php');
לא יודע אם כבר אמרתי, אבל הפונקציה redirect מעבירה כתובת.
הקונטרולר:
<?php
class AccountController extends CController
{
public $layout = 'header';
public function actions()
{
return array
(
'captcha' => array
(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'testLimit'=>3,
)
);
}
public function actionRegister()
{
$model = new RegisterForm();
if(isset($_POST['RegisterForm']))
{
$model->attributes = $_POST['RegisterForm'];
if($model->validate())
{
$account = new Account();
$account->username = $model->username;
$account->password = md5($model->password);
$account->email = $model->email;
$account->ip = Yii::app()->request->userHostAddress;
$account->save();
$this->redirect('index.php');
}
}
$this->render('register',array('model'=>$model));
}
}
?>
class AccountController extends CController
{
public $layout = 'header';
public function actions()
{
return array
(
'captcha' => array
(
'class'=>'CCaptchaAction',
'backColor'=>0xFFFFFF,
'testLimit'=>3,
)
);
}
public function actionRegister()
{
$model = new RegisterForm();
if(isset($_POST['RegisterForm']))
{
$model->attributes = $_POST['RegisterForm'];
if($model->validate())
{
$account = new Account();
$account->username = $model->username;
$account->password = md5($model->password);
$account->email = $model->email;
$account->ip = Yii::app()->request->userHostAddress;
$account->save();
$this->redirect('index.php');
}
}
$this->render('register',array('model'=>$model));
}
}
?>
אם יהיו תגובות יהיה חלק ז'.
תגובות לכתבה:
אני רוצה להוסיף שני דברים ממש חשובים.
1. קאפצ'ה לא באמת עוזרת נגד מכונות.. אף אחד לא יתקיף את האתר שלכם סתם ככה, כל עוד הוא לא פורום באיזשהי מערכת מוכנה, כמו שהיה כאן פעם עם smf. ברגע שמישהו יחליט להוסיף לכם קצת ספאם לאתר ויכתוב בוט במיוחד בשביל האתר שלכם - שום תמונה לא תעזור. התמונות האלה ניתנות לפענוח ועקיפה.
2. יש ב yii כמה סוגי וולדיטורים שאליהו תיאר למעלה.
אפשר להוסיף קישור לרשימת כל הוולדיטורים וכל הפרמטרים האפשריים שהם מקבלים
yii validators cheat sheet
http://yii.googlecode.com/files/yii-1.1.0-validator-cheatsheet.pdf
כמעט לכל וולידטור אפשר לתת פרמטר של message
עם הודעת שגיאה שתוצג במקרה והוזן תוכן שלא עובר וולידציה.
שוב תודה אליהו :)
ממליץ לא לכתוב עברית בתוך הקוד. גם מבחינת קידוד זה לא נכון וגם מבחינת תחזוקה - אנגלית היא השפה של הקידוד (כמו שרופאים עדיין כותבים בלטינית...)
המשך לכתוב, תודה על השיתוף.
אמיר סימן טוב
תודה ענקית, ממש חיכיתי בקוצר רוח!
לא יכול לחכות למדריך הבא :)!
שוב מדריך מצויין ושימושי!
אני כבר מחכה למדריך הבא בקוצר רוח! D:
תודה רבה אשמח אם תמשיך לרשום מדריכים מחכה לזה.
ולמגיב הראשון
intval:
אתה טועה וצודק בקשר לקפצה נכון זה קל לעקיפה אבל כל אחד שיש לו אתר חי וקיים יודע שיש אלפי בוטים שמסתובבים ברשת ומנסים להירשם ולפרסם ספאם באתרים.
ובלי קפצה אתה תקום יום אחד ותראה שנרשמו לך 20 אלף משתמשים לאתר
בכל מקרה הפתרון הכי טוב שמצאתי לזה היא לעשות מיני קפצה משלך כמו לשאול בעברית "כמה זה אחד ועוד אחד" וככה נפתרים מכמעט 100% מהבוטים
מי שיעקוף את זה הוא מי שתיכנן בוט במיוחד לאתר שלך
ולצורך זה יש אפשרויות אחרות
קמתי יום אחד וראיתי שנרשמו 121382 משתמשים :)
אני מסכים איתך לגמרי שבוטים מסתובבים ברשת ומנסים להירשם לאתרים, אבל ברוב המקרים מדובר בבוטים למערכות מוכנות, פורומים מוכנים ודברים אחרים.
הפתרון שלי מבוטים היה די פשוט, לשים שדה חבוי בשם email
בן אדם אמיתי לא ימלא שדה hidden לאומת כל הבוטים שהגיעו לאתר.
אם מישהו כותב בוט מיוחד לאתר שלך - אתה קצת בבעיה, אבל אתה יכול לנסות למשל את הקאפצה החדשה שלי https://github.com/intval/3Dcaptcha
סתם שאלה - איך אתרים גדולים מתומודדים עם בוטים? לדוגמה פייסבוק איך הם יתמודדו עם בוטים?
גוגל למשל מבקשת אחרי כמה ניסיונות כושלים של הזדהות להקליד recaptcha
אבל אין להם ממש מה עם מה להתמודד. הם פשוט נותנים api והצורך בבוטים נעלם :)
לא משנה כמה ספאם תשים לעצמך ב wall אנשים אחרים לא יראו אותו, אלה אם הם בעצמם ירצו.
אין להם תוכן פומבי כזה.
ובקשר לפייסבוק (וגם גוגל) בהרשמה צריך להכניס מספר פלאפון ומקבלים הודעת sms עם קוד
ככה שזה מסבך תעניינים לבוטים במיוחד אם בכל מספר אפשר להירשם רק עם חשבון אחד
הודעת ה-SMS של גוגל ופייסבוק לא עולה כסף, נכון?
"אוקיי, התנאים עובדים, הטופס עובד, אבל לא הוספנו את המשתמש לטופס!
עכשיו בשביל מה היה את המדריך הקודם? בשביל שנדע איך להוסיף טורים לטופס."
מה הכוונה להוסיף טורים לטופס?
כל הכבוד ותודה רבה על המדריכים. :)
אגב, אם מישהו יכול לתקן את פרצת ה-XSS הקבועה במדריכים זה יהיה נחמד. D:
כשערכתי, בטעות שכחתי לסגור את ה-BBcode של הבולד, וכל התגובות היו מובלטות. :)
להוסיף טורים למסד זה הכוונה להוסיף עוד שורה במסד נתונים שלנו (MySQL) מה שלמדנו במדריך הקודם
היה כתוב שם "להוסיף טורים לטופס", ולא למסד.
ובכל מקרה, יש הבדל בין טור לשורה. :)
אחלה מדריך ^^
מחכה להבא!
חלק ז' יעסוק בהתחברות ?
יהיה חלק ז' :-) ?
איך אני מוחק את ה "Get a new code" שנוצר לי יחד עם הקאפצ'ה ?
באופ כללי אתה
0. חושב עוד שלוש פעמים האם אתה באמת רוצה להוריד אותו והטקסט הזה מפריע לך או שמספיק לשנות לא קצת עיצוב ומיקום על ידי css, אחרי זה
1. פותח את הקוד של המחלקה שמייצרת את הטקסט הזה,
2. מסתכל איזה פונקציה עושה את זה,
3. כותב מחלקה חדשה לקאפצ'ה שיורשת מהמחלקה הקיימת
4. ודואג _לא להפעיל_ את הפונקציה שמייצרת את הטקסט
למה להגיד לי שאני אפס ?
ותודה -_-
החלטת שאמרו לך שאתה אפס בגלל שהתחלתי את המספור מאפס?
התחלתי אותו מאחד ואז החלטתי להוסיף עוד סעיף. במקום לערוך את כל שאר המספרים התחלתי מאפס.